package com.xiangyang.filter;

import com.alibaba.fastjson2.JSON;

import com.xiangyang.entity.dto.Result;
import com.xiangyang.entity.vo.JwtJubInfo;
import com.xiangyang.exception.CustomerAuthenticationException;
import com.xiangyang.handler.LoginFailureHandler;
import com.xiangyang.service.impl.UserDetailsServiceImpl;
import com.xiangyang.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private LoginFailureHandler loginFailureHandler;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String url = request.getRequestURI();
        if (url.contains("login") || url.contains("register")|| url.contains("forgetPassword")||url.contains("getCode")) {
            filterChain.doFilter(request, response);
            return;
        }
        try {
            this.validateToken(request);
            filterChain.doFilter(request, response);
        } catch (AuthenticationException e) {
            loginFailureHandler.onAuthenticationFailure(request, response, e);
        }


    }

    public void validateToken(HttpServletRequest request) {
        //判断请求头中有没有token
        String token = request.getHeader("token");
        if (Objects.isNull(token) || token.isEmpty()) {
            token = request.getParameter("token");
        }
        //判断请求路径中有没有token如果没有说明请求头中和请求路径中都没有则抛出异常
        if (Objects.isNull(token) || token.isEmpty()) {
            throw new CustomerAuthenticationException("token不存在");
        }
        //以下是解析token获取token中的信息哪到用户名

        JwtJubInfo TokenUserinfo = null;
        try {
            Claims cla = JwtUtil.parseJwt(token);
            TokenUserinfo = JSON.toJavaObject(cla.getSubject(), JwtJubInfo.class);
        } catch (ExpiredJwtException e) {
            throw new CustomerAuthenticationException("token令牌失效");
        } catch (Exception e) {
            throw new CustomerAuthenticationException("token解析失败");
        }
        loginStatus(token);
        if (TokenUserinfo.getUserName() != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(TokenUserinfo.getUserPhone());
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }


    }

    public void loginStatus(String token) {

        //先将String中的key为这个token的值获取到
        String redisToken = stringRedisTemplate.opsForValue().get(token);
        //这是获取这个key是否存在存在为true不存在为false
        boolean exists = stringRedisTemplate.hasKey(token);
        //如果存在且值为“”则抛出以下异常
        if (exists && redisToken.isEmpty()) {
            stringRedisTemplate.delete(token);
            throw new CustomerAuthenticationException("其他地点登陆，当前登陆以达到上线");
        }
        //如果不存在则抛出以下异常
        if (!exists) {
            throw new CustomerAuthenticationException("登陆失效请重新登陆");
        }
        //redis中续期用户有效时间
        if(redisTemplate.getExpire(token)<24 * 60 * 60L){
            stringRedisTemplate.expire(token, 2* 24 * 60 * 60L, TimeUnit.SECONDS);
        }

    }
}
